//
//  WBNetworkManager.swift
//  TYCWeiBo
//
//  Created by 中发 on 2018/6/4.
//  Copyright © 2018年 中发. All rights reserved.
//

import UIKit
import AFNetworking

/**
 如果日常开发中，发现网络请求返回的状态码是 405 ，不支持的网络请求方法
 -首先应该查找网络请求方法是否正确
 */
enum WBHttpMethod {
    case GET
    case POST
}
/// 网络管理工具
class WBNetworkManager: AFHTTPSessionManager {

    /// 静态区/常量/闭包
    //在第一次访问时，执行闭包，并将结构保存到shared中
    static let shared: WBNetworkManager = {
        //实例化对象
        let instance = WBNetworkManager()
        //设置相应反序列化支持的数据类型
        instance.responseSerializer.acceptableContentTypes?.insert("text/plain")
        //返回对象
        return instance
    }()
    
    lazy var userAccount = WBUserAccount()
    //用户登录标记（计算型属性）
    var userLogin: Bool {
      return userAccount.access_token != nil
    }
    
    /// 专门负责拼接Token处理的方法
    ///
    /// - Parameters:
    ///   - wbHttpMethod: GET/POST
    ///   - urlString: urlString
    ///   - parameters: 参数字典
    ///   - name: 上传文件使用的字段名，默认为nil ,不上传文件
    ///   - data: 上传文件的二进制数据，默认为nil ,不上传文件
    ///   - completion: 完成回调
    func tokenRequest(wbHttpMethod: WBHttpMethod = .GET,  urlString: String, parameters: [String: Any]?, name: String? = nil, data: Data? = nil, completion: @escaping (_ json: Any?, _ isSuccess: Bool) -> ()) {
        
        //处理token字典
        //1>判断token是否为nil，如果为nil就直接返回
        guard let token = userAccount.access_token else {
            //发送通知，提示用户登录
            //没有token，需要登录
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: nil)
            completion(nil, false)
            return
        }
        //2>判断参数字典是否存在，如果为nil，应该新建一个字典
        var parameters = parameters
        if parameters == nil {
            //实例化字典
            parameters = [String: Any]()
        }
        //3>设置参数字典
        parameters!["access_token"] = token
        //4>判断name 和 data
        if let name = name, let data = data {
            //上传文件
            upload(urlString: urlString, parameters: parameters, name: name, data: data, completion: completion)
        }else {
            
            //调用request发起真正的网络请求
            //        request(urlString: urlString, parameters: parameters!, completion: completion)
            request(wbHttpMethod: wbHttpMethod, urlString: urlString, parameters: parameters!, completion: completion)
        }
    }
    
    //MARK: - 封装 AFN 方法
    /// 上传文件必须是POST方法，GET只能获取数据
    /// 封装 AFN 的上传文件方法
    ///
    /// - Parameters:
    ///   - urlString: urlString
    ///   - parameters: 参数字典
    ///   - name: 接受上传数据的服务器字段（name - 要咨询公司的后台）‘pic’
    ///   - data: 要上传的二进制数据
    ///   - completion: 完成的回调
    func upload(urlString: String, parameters: [String: Any]?, name: String, data: Data, completion: @escaping (_ json: Any?, _ isSuccess: Bool) -> ()) {
        
        post(urlString, parameters: parameters, constructingBodyWith: { (formData) in
            //FIXME: 创建formData
            /**
             1.data:要上传的二进制数据
             2.name:服务器接收数据的字段
             3.fileName保存在服务器的文件名，大多数服务器，可以乱写，因为很多服务器，上传图片完成后，会生成缩略图，中图，大图...
             4.mimeType：告诉服务器上传文件的类型，如果不想告诉，可以使用 application-octet-stream .否则写 image/png image/jpg image/gif
             */
            formData.appendPart(withFileData: data, name: name, fileName: "XXX", mimeType: "application-octet-stream")
        }, progress: nil, success: { (_, json) in
            completion(json, true)
        }) { (task, error) in
            //针对403处理用户token过期
            if (task?.response as? HTTPURLResponse)?.statusCode == 403 {
                //发送通知，提示用户再次登录（本方法不知道被谁调用，谁接收到通知，谁处理）
                print("token过期了")
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: "bad Token")
            }
            print("网络请求错误 \(error)")
            completion(nil, false)
        }
    }
    
    //使用一个函数封装AF的GET/POST请求
    /// 封装AF的GET/POST请求
    ///
    /// - Parameters:
    ///   - wbHttpMethod: WBHttpMethod
    ///   - urlString: url
    ///   - parameters: 参数字典
    ///   - completion: 请求结果回调
    func request(wbHttpMethod: WBHttpMethod = .GET,  urlString: String, parameters: [String: Any]?, completion: @escaping (_ json: Any?, _ isSuccess: Bool) -> ()) {
        
        //成功回调
        let success = { (task: URLSessionDataTask, json: Any?) -> () in
            completion(json, true)
        }
        //失败回调
        let failure = { (task: URLSessionDataTask?, error: Error) -> () in
            //针对403处理用户token过期
            if (task?.response as? HTTPURLResponse)?.statusCode == 403 {
                //发送通知，提示用户再次登录（本方法不知道被谁调用，谁接收到通知，谁处理）
                print("token过期了")
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: "bad Token")
            }
            print("网络请求错误 \(error)")
            completion(nil, false)
        }
        if wbHttpMethod == .GET {
           
            get(urlString, parameters: parameters, progress: nil, success: success, failure: failure)

        }else {
            
            post(urlString, parameters: parameters, progress: nil, success: success, failure: failure)
        }
    }
}
